.586

.model flat, stdcall
option casemap:none

include 	windows.inc
include 	kernel32.inc
include 	masm32.inc
include 	msvcrt.inc
include 	shell32.inc
includelib 	masm32.lib
includelib 	kernel32.lib
includelib 	msvcrt.lib


my_printf	PROTO C	 args: VARARG
my_putchar	PROTO C  handle: dword, value: dword
my_strlen	PROTO C  string: dword
my_puts		PROTO C  handle: dword, string: dword

my_put_b	PROTO C  handle: dword, value: dword
my_put_h	PROTO C  handle: dword, value: dword
my_put_d	PROTO C  handle: dword, value: dword

getchar		PROTO C

.data
				char_to_put		BYTE 		4 dup(0)
				nchars_put		dword 		0h
				
				h_nums			BYTE		"0123456789ABCDEF", 0
				
				IHANDLE			dword 		0
				OHANDLE			dword 		0
				
				str1			byte		"best", 0
				str2			byte		"Vasya Pupkin", 0
				num1			dword		10d
				num2			dword		0EDAEDAh
				num3			dword		110011101b
				char1			byte		'!'
				format_test		byte 		"Hi, my %s friend, I'm %s %d and I love %x %b times %c%c%c", 0
.code
Start:
				invoke AllocConsole
				
				invoke	GetStdHandle, STD_OUTPUT_HANDLE
				mov dword ptr OHANDLE, eax
				invoke  GetStdHandle, STD_INPUT_HANDLE
				mov dword ptr IHANDLE, eax
				
				invoke my_printf,
					addr format_test,
					addr str1,
					addr str2,
					num1,
					num2,
					num3,
					dword ptr char1,
					dword ptr char1,
					dword ptr char1
					
				
				invoke getchar



;===============================================================================
; this proc puts a char in a handle given
;-------------------------------------------------------------------------------                                                                          
; Entry:	handle.
;			char value.
; Exit:		None.                                                                               
; Destr:	None.                                                                             
;===============================================================================

my_putchar		proc C 	handle: dword, value: dword

				push 	eax
				mov 	eax, dword ptr value
				mov 	byte ptr char_to_put, al
				pop 	eax
				
				invoke WriteConsole,
					handle,
					addr char_to_put,
					1,
					addr nchars_put,
					NULL
						
				pop eax
				ret	
my_putchar		endp

;===============================================================================
; this proc calculates length of a string given
;-------------------------------------------------------------------------------                                                                          
; Entry:	string ptr.
; Exit:		EAX = len.                                                                               
; Destr:	EAX, ECX.                                                                             
;===============================================================================

my_strlen		proc C  string: dword
				
				cld
				push edi
				push ebx
				
				mov edi, dword ptr string
				
				or edi, edi
				je strlen_stop
	
				mov ebx, edi
				xor eax, eax
				
				mov ecx, 0ffffffffh
				repne scasb
				
				sub edi, ebx
				mov eax, edi
				sub eax, 1
				
				
strlen_stop:
				pop ebx
				pop edi
strlen_Exit:	ret
my_strlen 		endp

;===============================================================================
; this proc puts a string in a handle given.
;-------------------------------------------------------------------------------                                                                          
; Entry:	handle.
;			string ptr.
; Exit:		None.                                                                               
; Destr:	None.                                                                             
;===============================================================================

my_puts			proc C  handle: dword, string: dword

				invoke my_strlen, dword ptr string
				
				invoke WriteConsole,
					handle,
					string,				
					eax,
					addr nchars_put,
					NULL
				
				ret
my_puts			endp

;===============================================================================
; this proc puts a number as a binary one in a handle given.
;-------------------------------------------------------------------------------                                                                          
; Entry:	handle.
;			num value.
; Exit:		None.                                                                               
; Destr:	EAX, ECX, EDX.                                                                             
;===============================================================================

my_put_b		proc C	handle: dword, value: dword

				mov eax, value
				mov ecx, 20h
b_Next:				
				rol eax, 1
				mov dl, al
				and dl, 1
				add dl, '0'      				
				
				mov byte ptr char_to_put, dl
				
				push ecx
				push eax
				invoke WriteConsole,
					handle,
					addr char_to_put,				
					1,
					addr nchars_put,
					NULL
				pop eax
				pop ecx
				
				loop b_Next

				ret
my_put_b 		endp

;===============================================================================
; this proc puts a number as a hexadronal one in a handle given.
;-------------------------------------------------------------------------------                                                                          
; Entry:	handle.
;			num value.
; Exit:		None.                                                                               
; Destr:	EAX, ECX, EDX.                                                                             
;===============================================================================

my_put_h		proc C  handle: dword, value: dword
				mov eax, value
				xor dh, dh
				mov ecx, 8
h_Next:
				mov ebx, offset h_nums
				rol eax, 4                 
				mov edx, eax
				and edx, 0fh
				add edx, offset h_nums  	
				
				mov edx, [edx]
				mov byte ptr char_to_put, dl
				
				push ecx
				push eax
				invoke WriteConsole,
					handle,
					addr char_to_put,				
					1,
					addr nchars_put,
					NULL
				pop eax
				pop ecx
				
				loop h_Next
	
				ret
my_put_h 		endp

;===============================================================================
; this proc puts a number as a decimal one in a handle given.
;-------------------------------------------------------------------------------                                                                          
; Entry:	handle.
;			num value.
; Exit:		None.                                                                               
; Destr:	EAX, EBX, ECX, EDX.                                                                             
;===============================================================================

my_put_d		proc C  handle: dword, value: dword
				mov eax, value
				xor ecx, ecx

d_Push:         xor edx, edx
				mov ebx, 10d
				div ebx                         
				push edx
				inc ecx

				test eax, eax
				je d_Break
                
				cmp ecx, 10h
				jb d_Push

d_Break:		mov bl, 01h			; SAY we don't need any nills yet.

d_Next: 		pop edx

				cmp dl, bl
				jb d_Continue		; if you don't need nill, but get it - GO AWAY.

				xor bl, bl 			; SAY nills become useful since now.
				add dl, '0'
				
				mov byte ptr char_to_put, dl
				
				push ecx
				push eax
				invoke WriteConsole,
					handle,
					addr char_to_put,				
					1,
					addr nchars_put,
					NULL
				pop eax
				pop ecx
				
d_Continue:		loop d_Next
				ret
my_put_d 		endp

;===============================================================================
; Printfas it is.
;-------------------------------------------------------------------------------                                                                          
; Entry:	format.
;			args
; Exit:		None.                                                                               
; Destr:	EAX, EBX, ECX, EDX, ESI.                                                                             
;===============================================================================

my_printf		proc C args: VARARG
				
				push ebp
                mov ebp, esp
                
                mov esi, [ebp+12]
                mov ebx, ebp
                add ebx, 12d
                
p_Iter:         mov al, byte ptr [esi]
				inc esi
				
                or al, al
                jz p_Stop
                
                cmp al, '%'
                je p_Service
                
                xor edx, edx
                mov dl, al
                
                push ebx
                push ebp
                push esi                
                invoke my_putchar,
                	OHANDLE,
                	edx  
                pop esi
                pop ebp
                pop ebx
                             
                jmp p_Iter
                
;--------------|'%' switch block. |---------------------------------------------;                
                
p_Service:      lodsb					; switch al {
                add ebx, 4				; we get next argument.
                
                cmp al, 's'				; case 's': put_string.
                je p_string 
                cmp al, 'c'				; case 'c': put_char.
                je p_char
                cmp al, 'b'				; case 'b': put_binary.
                je p_binary
                cmp al, 'd'				; case 'd': put_decimal.
                je p_decimal
                cmp al, 'x'				; case 'x': put_hexadronal.
                je p_hexadronal
                jne p_Fail				; default: goto Fail.
            	;|end of switch block.| ; }
                
p_string:		push esi
			 	push ebx
			 	push ebp			 	
                invoke my_puts,
                	OHANDLE,
                	[ebx]		; string: ESI. Destr-s: None
                pop ebp
                pop ebx	
                pop esi 
                jmp p_Iter
                
p_char:       	
				push esi
			 	push ebx
			 	push ebp
                invoke my_putchar,
                	OHANDLE,
                	[ebx]
                pop ebp
                pop ebx	
                pop esi					; char: DL. Destr-s: EAX.
                jmp p_Iter
                
p_binary:     	mov eax, [ebx]
                push esi
			 	push ebx
			 	push ebp					; We'll need EBX.
                invoke my_put_b,
                	OHANDLE,
                	eax
                pop ebp
                pop ebx	
                pop esi
                jmp p_Iter				; value: EAX. Destr-s: EAX, ECX, EDX
                
p_decimal:    	mov eax, [ebx]
                push esi
			 	push ebx
			 	push ebp				; We'll need EBX.
                invoke my_put_d,
                	OHANDLE,
                	eax
                pop ebp
                pop ebx	
                pop esi
                jmp p_Iter				; value: EAX. Destr-s: EAX, ECX, EDX.
                
p_hexadronal: 	mov eax, [ebx]
                push esi
			 	push ebx
			 	push ebp				; We'll need EBX.
                invoke my_put_h,
                	OHANDLE,
                	eax
                pop ebp
                pop ebx	
                pop esi
                jmp p_Iter              ; value: EAX. Destr-s: EAX, EBX, ECX, EDX.

p_Stop:         xor eax, eax
                jmp p_Exit
                
p_Fail:         mov eax, 0ffffffffh
                jmp p_Exit
                
p_Exit:         pop ebp
				ret
my_printf 		endp


end				Start